var DOMParser = window.DOMParser = function (options){
	this.options = options ||{locator:{}};
};

DOMParser.prototype.parseFromString = function(source,mimeType){
	var options = this.options;
	var sax =  new XMLReader();
	var domBuilder = options.domBuilder || new DOMHandler();//contentHandler and LexicalHandler
	var errorHandler = options.errorHandler;
	var locator = options.locator;
	var defaultNSMap = options.xmlns||{};
	var isHTML = /\/x?html?$/.test(mimeType);//mimeType.toLowerCase().indexOf('html') > -1;
  	var entityMap = isHTML?htmlEntity.entityMap:{'lt':'<','gt':'>','amp':'&','quot':'"','apos':"'"};
	if(locator){
		domBuilder.setDocumentLocator(locator)
	}
	
	sax.errorHandler = this._buildErrorHandler(errorHandler,domBuilder,locator);
	sax.domBuilder = options.domBuilder || domBuilder;
	if(isHTML){
		defaultNSMap['']= 'http://www.w3.org/1999/xhtml';
	}
	defaultNSMap.xml = defaultNSMap.xml || 'http://www.w3.org/XML/1998/namespace';
	if(source){
		sax.parse(source,defaultNSMap,entityMap);
	}else{
		sax.errorHandler.error("invalid doc source");
	}
	return domBuilder.doc;
};

DOMParser.prototype._buildErrorHandler = function (errorImpl,domBuilder,locator){
	if(!errorImpl){
		if(domBuilder instanceof DOMHandler){
			return domBuilder;
		}
		errorImpl = domBuilder ;
	}
	var errorHandler = {};
	var isCallback = errorImpl instanceof Function;
	locator = locator||{};
	function build(key){
		var fn = errorImpl[key];
		if(!fn && isCallback){
			fn = errorImpl.length === 2?function(msg){errorImpl(key,msg)}:errorImpl;
		}
		errorHandler[key] = fn && function(msg){
			fn('[xmldom '+key+']\t'+msg+this._locator(locator));
		}||function(){};
	}
	build('warning');
	build('error');
	build('fatalError');
	return errorHandler;
};

//console.log('#\n\n\n\n\n\n\n####')
/**
 * +ContentHandler+ErrorHandler
 * +LexicalHandler+EntityResolver2
 * -DeclHandler-DTDHandler 
 * 
 * DefaultHandler:EntityResolver, DTDHandler, ContentHandler, ErrorHandler
 * DefaultHandler2:DefaultHandler,LexicalHandler, DeclHandler, EntityResolver2
 * @link http://www.saxproject.org/apidoc/org/xml/sax/helpers/DefaultHandler.html
 */
function DOMHandler() {
    this.cdata = false;
}

/**
 * @see org.xml.sax.ContentHandler#startDocument
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ContentHandler.html
 */ 
DOMHandler.prototype = {
    _position: function (locator, node) {
        node.lineNumber = locator.lineNumber;
        node.columnNumber = locator.columnNumber;
    },

    startDocument: function () {
        this.doc = new DOMImplementation().createDocument(null, null, null);
        if (this.locator) {
            this.doc.documentURI = this.locator.systemId;
        }
    },
    startElement: function (namespaceURI, localName, qName, attrs) {
        var doc = this.doc;
        var el = doc.createElementNS(namespaceURI, qName || localName);
        var len = attrs.length;
        this._appendElement(this, el);
        this.currentElement = el;

        this.locator && this._position(this.locator, el);
        for (var i = 0; i < len; i++) {
            var namespaceURI = attrs.getURI(i);
            var value = attrs.getValue(i);
            var qName = attrs.getQName(i);
            var attr = doc.createAttributeNS(namespaceURI, qName);
            this.locator && this._position(attrs.getLocator(i), attr);
            attr.value = attr.nodeValue = value;
            el.setAttributeNode(attr)
        }
    },
    endElement: function (namespaceURI, localName, qName) {
        var current = this.currentElement;
        var tagName = current.tagName;
        this.currentElement = current.parentNode;
    },
    startPrefixMapping: function (prefix, uri) {
    },
    endPrefixMapping: function (prefix) {
    },
    processingInstruction: function (target, data) {
        var ins = this.doc.createProcessingInstruction(target, data);
        this.locator && this._position(this.locator, ins);
        this._appendElement(this, ins);
    },
    ignorableWhitespace: function (ch, start, length) {
    },
    characters: function (chars, start, length) {
        chars = this._toString.apply(this, arguments);
        //console.log(chars)
        if (chars) {
            if (this.cdata) {
                var charNode = this.doc.createCDATASection(chars);
            }
            else {
                var charNode = this.doc.createTextNode(chars);
            }
            if (this.currentElement) {
                this.currentElement.appendChild(charNode);
            }
            else if (/^\s*$/.test(chars)) {
                this.doc.appendChild(charNode);
                //process xml
            }
            this.locator && this._position(this.locator, charNode)
        }
    },
    skippedEntity: function (name) {
    },
    endDocument: function () {
        this.doc.normalize();
    },
    setDocumentLocator: function (locator) {
        if (this.locator = locator) {// && !('lineNumber' in locator)){
            locator.lineNumber = 0;
        }
    },
    //LexicalHandler
    comment: function (chars, start, length) {
        chars = this._toString.apply(this, arguments);
        var comm = this.doc.createComment(chars);
        this.locator && this._position(this.locator, comm);
        this._appendElement(this, comm);
    },

    startCDATA: function () {
        //used in characters() methods
        this.cdata = true;
    },
    endCDATA: function () {
        this.cdata = false;
    },

    startDTD: function (name, publicId, systemId) {
        var impl = this.doc.implementation;
        if (impl && impl.createDocumentType) {
            var dt = impl.createDocumentType(name, publicId, systemId);
            this.locator && this._position(this.locator, dt);
            this._appendElement(this, dt);
        }
    },
    /**
     * @see org.xml.sax.ErrorHandler
     * @link http://www.saxproject.org/apidoc/org/xml/sax/ErrorHandler.html
     */
    warning: function (error) {
        console.warn('[xmldom warning]\t' + error, this._locator(this.locator));
    },
    error: function (error) {
        console.error('[xmldom error]\t' + error, this._locator(this.locator));
    },
    fatalError: function (error) {
        console.error('[xmldom fatalError]\t' + error, this._locator(this.locator));
        throw error;
    },

    /* Private static helpers treated below as private instance methods, so don't need to add these to the public API; we might use a Relator to also get rid of non-standard public properties */
    _appendElement: function (hander, node) {
        if (!hander.currentElement) {
            hander.doc.appendChild(node);
        }
        else {
            hander.currentElement.appendChild(node);
        }
    }, //appendChild and setAttributeNS are preformance key
    _locator: function (l) {
        if (l) {
            return '\n@' + (l.systemId || '') + '#[line:' + l.lineNumber + ',col:' + l.columnNumber + ']'
        }
    },
    _toString: function (chars, start, length) {
        if (typeof chars === 'string') {
            return chars.substr(start, length)
        }
        else {//java sax connect width xmldom on rhino(what about: "? && !(chars instanceof String)")
            if (chars.length >= start + length || start) {
                return new java.lang.String(chars, start, length) + '';
            }
            return chars;
        }
    }
};

/*
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/LexicalHandler.html
 * used method of org.xml.sax.ext.LexicalHandler:
 *  #comment(chars, start, length)
 *  #startCDATA()
 *  #endCDATA()
 *  #startDTD(name, publicId, systemId)
 *
 *
 * IGNORED method of org.xml.sax.ext.LexicalHandler:
 *  #endDTD()
 *  #startEntity(name)
 *  #endEntity(name)
 *
 *
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/DeclHandler.html
 * IGNORED method of org.xml.sax.ext.DeclHandler
 * 	#attributeDecl(eName, aName, type, mode, value)
 *  #elementDecl(name, model)
 *  #externalEntityDecl(name, publicId, systemId)
 *  #internalEntityDecl(name, value)
 * @link http://www.saxproject.org/apidoc/org/xml/sax/ext/EntityResolver2.html
 * IGNORED method of org.xml.sax.EntityResolver2
 *  #resolveEntity(String name,String publicId,String baseURI,String systemId)
 *  #resolveEntity(publicId, systemId)
 *  #getExternalSubset(name, baseURI)
 * @link http://www.saxproject.org/apidoc/org/xml/sax/DTDHandler.html
 * IGNORED method of org.xml.sax.DTDHandler
 *  #notationDecl(name, publicId, systemId) {};
 *  #unparsedEntityDecl(name, publicId, systemId, notationName) {};
 */
"endDTD,startEntity,endEntity,attributeDecl,elementDecl,externalEntityDecl,internalEntityDecl,resolveEntity,getExternalSubset,notationDecl,unparsedEntityDecl".replace(/\w+/g,function(key) {
    DOMHandler.prototype[key] = function () {
        return null
    }
});

//if(typeof require == 'function'){
BK.Script.loadlib('GameRes://libs/xmldom/entities.js');
BK.Script.loadlib('GameRes://libs/xmldom/sax.js');
BK.Script.loadlib('GameRes://libs/xmldom/dom.js');
//}
